package com.qf.controller;


import com.alibaba.fastjson.JSONObject;
import com.qf.captcha.CaptchaCodeManager;
import com.qf.pojo.DtsAdmin;
import com.qf.service.DtsPermissionService;
import com.qf.service.DtsRoleService;
import com.qf.util.*;
import com.qf.util.Base64;
import com.qf.util.UUID;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;


import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * @author ZhangYuJie
 * projectName:shop_manage
 * time:2022/5/16 14:39
 * description:
 */
@RestController
//@CrossOrigin("*") 只会对当前有效
@CrossOrigin("*")
@RequestMapping("/admin/auth")
public class DtsAdminAuthController {
    private static final Logger logger = LoggerFactory.getLogger(DtsAdminAuthController.class);

    @Autowired
    private DtsRoleService roleService;

    @Autowired
    private DtsPermissionService permissionService;

    @Autowired
    private ApplicationContext context;

    private HashMap<String, String> systemPermissionsMap = null;

/**
* 用户登录功能
*/
    @RequestMapping("/login")
    public Object login(@RequestBody Map<String,String> map, HttpSession session){
        String code=map.get("code");
        String password=map.get("password");
        String username=map.get("username");
        String uuid=map.get("uuid");

        String cachedCaptcha = CaptchaCodeManager.getCachedCaptcha(uuid);
        if(code == null || !code.equalsIgnoreCase(cachedCaptcha)) {
            return ResponseUtil.fail(-1, "验证码已过期或验证码错误!!");
        }

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            //在控制台打印错误的堆栈信息,方便解决问题的
            e.printStackTrace();
            return ResponseUtil.fail(-1, "未知的账户");
        } catch (LockedAccountException e){
            e.printStackTrace();
            return ResponseUtil.fail(-1, "账户已锁定");
        } catch (CredentialsException e){
            e.printStackTrace();
            return ResponseUtil.fail(-1, "密码错误");
        }

        System.out.println(subject.hasRole("超级管理员"));
        System.out.println(subject.isPermitted("admin:category:read"));

        return ResponseUtil.ok(session.getId());
    }

    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public Object getCode(HttpServletResponse response) throws IOException {
        //1. 生成随机字串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(2);
        //2. 验证码唯一标识
        String uuid = UUID.randomUUID().toString(true);
        //3. 验证码存储到内存中
        boolean successful = CaptchaCodeManager.addToCache(uuid, verifyCode,10);
        //4. 判断验证码是否存储成功
        if (!successful) {
            logger.error("请求验证码出错:{}", AdminResponseCode.AUTH_CAPTCHA_FREQUENCY.desc());
            return AdminResponseUtil.fail(AdminResponseCode.AUTH_CAPTCHA_FREQUENCY);
        }
        //5. 生成图片
        int w = 111, h = 36;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        VerifyCodeUtils.outputImage(w, h, stream, verifyCode);

        //6. 将图片唯一id和图片内容返回
        try {
            Map<String, Object> data = new HashMap<>();
            data.put("uuid", uuid);
            data.put("img", Base64.encode(stream.toByteArray()));
            return ResponseUtil.ok(data);
        } catch (Exception e){
            e.printStackTrace();
            return ResponseUtil.serious();
        } finally {
            stream.close();
        }
    }

    /*
     * 用户注销
     */
    @RequiresAuthentication
    @PostMapping("/logout")
    public Object login() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();

       logger.info("【请求结束】系统管理->用户注销,响应结果:{}", JSONObject.toJSONString(currentUser.getSession().getId()));
        return ResponseUtil.ok();
    }

    /**
     * 用户登录后进入此方法获取用户名, 角色, 权限信息
     * @return
     */
    @RequiresAuthentication
    @GetMapping("/info")
    public Object info() {
        //1. 从shiro框架中获取当前登录用户对象
        Subject currentUser = SecurityUtils.getSubject();
        DtsAdmin admin = (DtsAdmin) currentUser.getPrincipal();

        //2. 获取当前用户名和用户头像
        Map<String, Object> data = new HashMap<>();
        data.put("name", admin.getUsername());
        data.put("avatar", admin.getAvatar());

        //3. 获取当前用户角色id数组
        Integer[] roleIds = admin.getRoleIds();
        //4. 获取当前角色名字集合
        Set<String> roles = roleService.queryByIds(roleIds);
        //5. 获取当前权限字符串集合
        Set<String> permissions = permissionService.queryByRoleIds(roleIds);
        data.put("roles", roles);

        //6. 这里需要转换perms结构，因为对于前端API形式的权限更容易理解
        data.put("perms", toAPI(permissions));

        logger.info("【请求结束】系统管理->用户信息获取,响应结果:{}", JSONObject.toJSONString(data));
        return ResponseUtil.ok(data);
    }






    /**
     * 将权限字符串集合转换成api形式的权限集合
     * @param permissions
     * @return
     */
    private Collection<String> toAPI(Set<String> permissions) {
        if (systemPermissionsMap == null) {
            systemPermissionsMap = new HashMap<>();
            //final String basicPackage = "com.qiguliuxing.dts.admin";
            final String basicPackage = "com.qf.admin";
            List<Permission> systemPermissions = PermissionUtil.listPermission(context, basicPackage);
            for (Permission permission : systemPermissions) {
                String perm = permission.getRequiresPermissions().value()[0];
                String api = permission.getApi();
                systemPermissionsMap.put(perm, api);
            }
        }

        Collection<String> apis = new HashSet<>();
        for (String perm : permissions) {
            String api = systemPermissionsMap.get(perm);
            apis.add(api);

            if (perm.equals("*")) {
                apis.clear();
                apis.add("*");
                return apis;
                // return systemPermissionsMap.values();
            }
        }
        return apis;
    }

    /**
     * 权限不足的请求处理接口
     * @return
     */
    @GetMapping("/401")
    public Object page401() {
        return ResponseUtil.unlogin();
    }

    /**
     * 登录成功请求首页的接口
     * @return
     */
    @GetMapping("/index")
    public Object pageIndex() {
        return ResponseUtil.ok();
    }

    /**
     * 对于某个资源没有操作权限的处理接口
     * @return
     */
    @GetMapping("/403")
    public Object page403() {
        return ResponseUtil.unauthz();
    }
}
